package com.xxx.video.commen.views.recyclerviews;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

public class RefreshRecyclerView extends RecyclerView {
    /**
     * is can refresh(default can refresh)
     */
    private boolean pullRefreshEnabled = true;
    /**
     * is can load more(default can load more)
     */
    private boolean loadMoreEnabled = true;
    /**
     * pull rate if the value ++ will difficult
     */
    private static final float DRAG_RATE = 2;
    /**
     * refresh or load more listener
     */
    private OnRecyclerViewRefreshOrLoadMoreListener mOnRecyclerViewRefreshOrLoadMoreListener;
    /**
     * status
     */
    private RefreshRecyclerViewState mRefreshRecyclerViewState = RefreshRecyclerViewState.IDLE;
    /**
     * header
     */
    private RefreshHeadView mRefreshHeadView;
    /**
     * foot
     */
    private LoadMoreFootView mLoadMoreFootView;
    /**
     * last y(default-1)
     */
    private float mLastY = -1;
    /**
     * wrap adapter
     */
    private WrapAdapter mWrapAdapter;
    /**
     * data observer
     */
    private final AdapterDataObserver mDataObserver = new DataObserver();
    /**
     * refresh header type
     */
    private static final int TYPE_REFRESH_HEADER = -5;
    /**
     * load more type
     */
    private final int TYPE_LOAD_MORE_FOOTER = -3;

    /**
     * diy status
     */
    public enum RefreshRecyclerViewState {
        /**
         * default
         */
        IDLE,
        /**
         * refresh ing
         */
        REFRESH_ING
    }

    public RefreshRecyclerView(Context context) {
        super(context);
        /*
         * init
         */
        init(context);
    }

    public RefreshRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        /*
         * init
         */
        init(context);
    }

    public RefreshRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        /*
         * init
         */
        init(context);
    }

    /**
     * init
     *
     * @param context context
     */
    private void init(Context context) {
        /*
         * header view
         */
        mRefreshHeadView = new RefreshHeadView(context);
        /*
         * foot view
         */
        mLoadMoreFootView = new LoadMoreFootView(context);
    }

    /**
     * change
     *
     * @param state state
     */
    @Override
    public void onScrollStateChanged(int state) {
        super.onScrollStateChanged(state);
        /*
         *
         */
        if (state == RecyclerView.SCROLL_STATE_IDLE && mOnRecyclerViewRefreshOrLoadMoreListener != null && loadMoreEnabled && mRefreshRecyclerViewState != RefreshRecyclerViewState.REFRESH_ING) {
            /*
             *
             */
            LayoutManager layoutManager = getLayoutManager();
            /*
             *
             */
            int lastVisibleItemPosition;
            /*
             *
             */
            if (layoutManager instanceof GridLayoutManager) {
                lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                /*
                 *
                 */
                int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
                ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
                lastVisibleItemPosition = findMax(into);
            } else {
                /*
                 *
                 */
                lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
            }

            /*
             *
             */
            if (layoutManager.getChildCount() > 0
                    && lastVisibleItemPosition >= layoutManager.getItemCount() - 2
                    && layoutManager.getItemCount() > layoutManager.getChildCount()
                    && mRefreshHeadView.getRefreshState() != RefreshHeadView.STATE_REFRESH_ING) {
                /*
                 *
                 */
                mLoadMoreFootView.setState(LoadMoreFootView.STATE_LOAD_ING);
                /*
                 *
                 */
                mOnRecyclerViewRefreshOrLoadMoreListener.onRecyclerviewLoadMore();
            }
        }
    }

    /**
     *
     *
     * @param adapter  adapter
     */
    @Override
    public void setAdapter(Adapter adapter) {
        mWrapAdapter = new WrapAdapter(adapter);
        super.setAdapter(mWrapAdapter);
        adapter.registerAdapterDataObserver(mDataObserver);
        mDataObserver.onChanged();
    }

    private class WrapAdapter extends Adapter<ViewHolder> {
        private Adapter adapter;

        public WrapAdapter(Adapter adapter) {
            this.adapter = adapter;
        }

        /**
         *
         *
         * @param position position
         * @return =
         */
        @Override
        public int getItemViewType(int position) {
            if (isRefreshHeader(position)) {
                return TYPE_REFRESH_HEADER;
            }
            if (isFooter(position)) {
                return TYPE_LOAD_MORE_FOOTER;
            }
            int adjPosition = position - 1;
            int adapterCount;
            if (adapter != null) {
                adapterCount = adapter.getItemCount();
                if (adjPosition < adapterCount) {
                    return adapter.getItemViewType(adjPosition);
                }
            }
            return super.getItemViewType(position);
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_REFRESH_HEADER) {
                return new SimpleViewHolder(mRefreshHeadView);
            }
            if (viewType == TYPE_LOAD_MORE_FOOTER) {
                return new SimpleViewHolder(mLoadMoreFootView);
            }
            return adapter.onCreateViewHolder(parent, viewType);
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            /*
             *
             */
            if (position == 0) {
                return;
            }
            int adjPosition = position - 1;
            int adapterCount;
            if (adapter != null) {
                adapterCount = adapter.getItemCount();
                if (adjPosition < adapterCount) {
                    adapter.onBindViewHolder(holder, adjPosition);
                }
            }
        }

        /**
         *
         *
         * @return data
         */
        @Override
        public int getItemCount() {
            if (adapter != null) {
                return 2 + adapter.getItemCount();
            } else {
                return 2;
            }
        }

        @Override
        public long getItemId(int position) {
            if (adapter != null && position >= 1) {
                int adjPosition = position - 1;
                int adapterCount = adapter.getItemCount();
                if (adjPosition < adapterCount) {
                    return adapter.getItemId(adjPosition);
                }
            }
            return -1;
        }

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            LayoutManager manager = recyclerView.getLayoutManager();
            if (manager instanceof GridLayoutManager) {
                final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return (position == 0 || isFooter(position))
                                ? gridManager.getSpanCount() : 1;
                    }
                });
            }
        }

        @Override
        public void onViewAttachedToWindow(ViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            if (layoutParams != null
                    && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams
                    && (holder.getLayoutPosition() == 0 || isFooter(holder.getLayoutPosition()))) {
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) layoutParams;
                p.setFullSpan(true);
            }
        }

        /**
         *
         *
         * @param position position
         * @return boolean
         */
        boolean isRefreshHeader(int position) {
            return position == 0;
        }

        /**
         *
         *
         * @param position position
         * @return
         */
        boolean isFooter(int position) {
            return position < getItemCount() && position >= getItemCount() - 1;
        }

        @Override
        public void registerAdapterDataObserver(AdapterDataObserver observer) {
            if (adapter != null) {
                adapter.registerAdapterDataObserver(observer);
            }
        }

        @Override
        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
            if (adapter != null) {
                adapter.unregisterAdapterDataObserver(observer);
            }
        }

        private class SimpleViewHolder extends ViewHolder {
            SimpleViewHolder(View itemView) {
                super(itemView);
            }
        }
    }

    /**
     *
     */
    private class DataObserver extends AdapterDataObserver {
        @Override
        public void onChanged() {
            if (mWrapAdapter != null) {
                mWrapAdapter.notifyDataSetChanged();
            }
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
        }

    }

    /**
     *
     *
     * @param e e
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (mLastY == -1) {
            mLastY = e.getRawY();
        }
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                /*
                 *
                 */
                mLastY = e.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                /*
                 *
                 */
                final float deltaY = e.getRawY() - mLastY;
                mLastY = e.getRawY();
                /*
                 *
                 */
                if (isHaveRefreshHead() && pullRefreshEnabled) {
                    mRefreshHeadView.onMove(deltaY / DRAG_RATE);
                    if (mRefreshHeadView.getVisibleHeight() > 0 && mRefreshHeadView.getRefreshState() < RefreshHeadView.STATE_REFRESH_ING) {
                        return false;
                    }
                }
                break;
            default:
                /*
                 *
                 */
                mLastY = -1;
                /*
                 *
                 */
                if (isHaveRefreshHead() && pullRefreshEnabled) {
                    /*
                     *
                     */
                    if (mRefreshHeadView.releaseAction()) {
                        /*
                         * set refreshing state
                         */
                        mRefreshRecyclerViewState = RefreshRecyclerViewState.REFRESH_ING;
                        if (mOnRecyclerViewRefreshOrLoadMoreListener != null) {
                            mOnRecyclerViewRefreshOrLoadMoreListener.onRecyclerviewRefresh();
                        }
                    }
                }
                break;
        }
        return super.onTouchEvent(e);
    }

    /**
     * is have head
     *
     * @return is have head
     */
    private boolean isHaveRefreshHead() {
        return mRefreshHeadView != null && mRefreshHeadView.getParent() != null;
    }

    /**
     * set max vaule
     *
     * @param into data
     * @return max value
     */
    private int findMax(int[] into) {
        int max = into[0];
        for (int value : into) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }

    /**
     * listener
     */
    public interface OnRecyclerViewRefreshOrLoadMoreListener {
        /**
         * refresh listener
         */
        void onRecyclerviewRefresh();

        /**
         * load more listener
         */
        void onRecyclerviewLoadMore();
    }

    /**
     * set listener
     *
     * @param onRecyclerViewRefreshOrLoadMoreListener listener
     */
    public void setOnRecyclerViewRefreshOrLoadMoreListener(OnRecyclerViewRefreshOrLoadMoreListener onRecyclerViewRefreshOrLoadMoreListener) {
        mOnRecyclerViewRefreshOrLoadMoreListener = onRecyclerViewRefreshOrLoadMoreListener;
    }

    /**
     * set is can refresh
     *
     * @param pullRefreshEnabled is can refresh
     */
    public void setPullRefreshEnabled(boolean pullRefreshEnabled) {
        this.pullRefreshEnabled = pullRefreshEnabled;
    }

    /**
     * set is can load more
     *
     * @param loadMoreEnabled is can load more
     */
    public void setLoadMoreEnabled(boolean loadMoreEnabled) {
        this.loadMoreEnabled = loadMoreEnabled;
    }

    /**
     * reset state
     */
    public void resetState() {
        setRefreshComplete();
        setLoadMoreComplete();
    }

    /**
     * set refresh finish
     */
    public void setRefreshComplete() {
        /*
         * default status
         */
        mRefreshRecyclerViewState = RefreshRecyclerViewState.IDLE;
        mRefreshHeadView.refreshComplete();
    }

    /**
     * set load more complete
     */
    public void setLoadMoreComplete() {
        mLoadMoreFootView.setState(LoadMoreFootView.STATE_LOAD_COMPLETE);
    }

    /**
     * set load more no more data
     */
    public void setNoMoreData(){
        mLoadMoreFootView.setState(LoadMoreFootView.STATE_LOAD_NO_MORE_DATA);

    }
}
